﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace 生成者和消费者模式Form
{
    public class Work
    {
        public Work()
        {
            StopFlag = false;
        }

        public void Start()
        {
            StopFlag = false;
            StartDemo();
        }

        public void Stop()
        {
            StopFlag = true;
        }

        public class TaskInfo
        {
            public int Index;

            public TaskInfo()
            {
            }

            public TaskInfo(int index)
            {
                this.Index = index;
            }
        }

        private static bool StopFlag = false;
        private int ProducerNumber = 1;
        private int ConsumerNumber = 3;

        private Queue<TaskInfo> TaskQueue = new Queue<TaskInfo>();
        private Semaphore TaskSemaphore = new Semaphore(0, 256);

        private object myLock = new object();

        public event ShowTextDelegate ShowTextEvent;

        private void StartDemo()
        {
            StartProducer(ProducerNumber);
            Thread.Sleep(2000);
            StartConsumer(ConsumerNumber);
        }

        private void StartProducer(int num)
        {
            for (int i = 0; i < num; i++)
            {
                Thread t = new Thread(new ThreadStart(Producer));
                t.Name = "Producer_" + (i + 1);
                t.Start();
            }
        }

        private void StartConsumer(int num)
        {
            for (int i = 0; i < num; i++)
            {
                Thread t = new Thread(new ParameterizedThreadStart(this.Consumer));
                t.Name = "Consumer_" + (i + 1);
                t.IsBackground = true;
                t.Start(i + 1);
            }
        }

        private void Producer()
        {
            int i = 0;
            while (!StopFlag)
            {
                TaskInfo Task = new TaskInfo(++i);
                lock (myLock)
                {
                    TaskQueue.Enqueue(Task);
                }
                TaskSemaphore.Release(1);

                string AddText = String.Format("Task {0} was Produced.\r\n", Task.Index);
                ShowTextEvent.Invoke(1, AddText);

                Thread.Sleep(1000);
            }
        }

        private void Consumer(object data)
        {
            int Index = (int)data;
            TaskInfo GetTask = null;

            while (true)
            {
                TaskSemaphore.WaitOne();
                lock (myLock)
                {
                    GetTask = TaskQueue.Dequeue();
                }

                string AddStr = String.Format("Consumer {0} take Task {1}\r\n", Index, GetTask.Index);
                ShowTextEvent.Invoke(Index + 1, AddStr);
                Random r = new Random();
                Thread.Sleep(r.Next(5) * 1000);
            }
        }
    }
}